SPDX-FileCopyrightText: 2018 Charles Mestdagh & Michael Hoebeke SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be
SPDX-License-Identifier: GPL-3.0-or-later
STEVE REICH - PIANO PHASE Interprétation formelle par modèle procédural par Michael Hoebeke et Charles Mestdagh AIM JURY Janvier 2019
import bpy
from bpy import context as C
from bpy import data as D
from bpy import ops as O
import math
from math import radians
from math import cos
from math import sin
import randomNETTOYAGE PRELIMINAIRE
O.object.select_all(action="SELECT")
O.object.delete()FONCTIONS
Definition de la fonction de création de camera en projection parallele if canon == ‘trimetrie’: #OK
def axoCam(projection, canon):
    bpy.ops.object.camera_add()
    maScene = bpy.context.scene.render
    monAxoCam = bpy.context.object
    monAxoCam.data.type = "ORTHO"
    monAxoCam.data.ortho_scale = 30
    if projection == "axonometrique":
        if canon == "isometrie":  # OK
            monAxoCam.name = "axoIsometrie"
            monAxoCam.rotation_euler = (radians(54.74), 0.0, radians(45))
            monAxoCam.location = (10.0, -10.0, 10.0)
            maScene.pixel_aspect_x = 1
        if canon == "dimetrie":  # OK
            monAxoCam.name = "axoDimetrie"
            monAxoCam.rotation_euler = (radians(60), 0.0, radians(23))
            monAxoCam.location = (5.53, -13.04, 8.18)
            maScene.pixel_aspect_x = 1monAxoCam.name = 'axoTrimetrie'
monAxoCam.rotation_euler = (radians(67), 0.0, radians(34))   
monAxoCam.location = (8.59, -12.734, 6.52)
                maScene.pixel_aspect_x = 1"""
        if canon == "trimetrie":
            monAxoCam.name = "axoTrimetrie"
            monAxoCam.rotation_euler = (radians(67), 0.0, radians(34))
            monAxoCam.location = (17, -20, 5)
            maScene.pixel_aspect_x = 1
#DIVIDER
#DIVIDER
def make_cube(coord=(0, 0, 0), size=(1, 1, 1), name="Cube"):
    """Makes a capsule in coord(x,y,z)
    of size(x,y,z)
    and name'name'"""
    add_cube(coord)
    scale_cube(size)
    rename_cube(name)
    return None
#DIVIDER
def add_cube(coord):
    """adds a cube
    default position (0,0,0) tuple
    default radius 0.5 int"""
    O.mesh.primitive_cube_add(radius=0.5, location=coord)
    return None
#DIVIDER
def scale_cube(size):
    """scales a cube
    arg tuple
    cube selected!"""
    O.transform.resize(value=size)
    return None
#DIVIDER
def rename_cube(name):
    """new name for selected cube
    object and mesh affected"""
    D.objects["Cube"].name = name
    C.object.data.name = name  # no other way?
    return None
#DIVIDER
def get_objects_with_name(name):
    """returns a list of objects
    containing <name> in D.object.name"""
    objects_list = []  # c.f. next fuction for shorter method
    for item in D.objects:
        if name in item.name:
            objects_list.append(item)
    return objects_list
#DIVIDER
def get_highest(name):
    """returns a list containing
    the objects with max z value"""
    objects_list = get_objects_with_name(name)
#DIVIDER
    max_z = max([object.location.z for object in objects_list])
#DIVIDER
    return [item for item in objects_list if item.location.z == max_z]
#DIVIDER
#DIVIDER
#DIVIDER
"""Introduire ici la partition du morceau désiré, chaque note correspondant à une hauteur"""
#DIVIDER
partition = [1, 2, 5, 6, 7, 2, 1, 6, 5, 2, 7, 6]
nompartition = "Piano Phase Partie 1"
modificateur = 1.5
#DIVIDER
print(
    "\n \n \n STEVE REICH - PIANO PHASE \n interpretation formelle par modele procedural \n Partition de base:",
    nompartition,
    "-",
    partition,
    "- modificateur axe z:",
    modificateur,
)
#DIVIDER
x = int(len(partition))
pianiste1 = []
for i in range(0, x + 1):
    pianiste1.append(partition)
#DIVIDER
pianiste2 = []
copiepartition = partition[:]
for i in range(0, x + 1):
    note1 = copiepartition[:i]
    nbrdenotesajout = len(note1)
    ajout = partition + note1
    del ajout[:i]
    pianiste2.append(ajout)
#DIVIDER
ecarts = []
for i in range(0, x + 1):  # nbr de temps
    for j in range(0, x):  # nbr de notes dans la partition
        p1 = pianiste1[i]
        notep1 = p1[j]
        p2 = pianiste2[i]
        notep2 = p2[j]
        if notep1 >= notep2:
            ecart = (notep1 - notep2) * modificateur
        else:
            ecart = (notep2 - notep1) * modificateur
        ecarts.append(ecart)
#DIVIDER
minmax = []
for i in range(0, x + 1):  # nbr de temps
    for j in range(0, x):  # nbr de notes dans la partition
        p1 = pianiste1[i]
        notep1 = p1[j]
        p2 = pianiste2[i]
        notep2 = p2[j]
        minmax.append([notep1, notep2])
#DIVIDER
notemax = max(partition)
notemin = min(partition)
valeurecartneutre = notemax + notemin
positionecarts = []
for i in range(0, x + 1):  # nbr de temps
    for j in range(0, x):  # nbr de notes dans la partition
        p1 = pianiste1[i]
        notep1 = p1[j]
        p2 = pianiste2[i]
        notep2 = p2[j]
        if notep1 == notep2:
            valeurecart = 0
            diffvaleurneutre = 0
        else:
            valeurecart = notep1 + notep2
            diffvaleurneutre = valeurecart - valeurecartneutre
        positionecarts.append(diffvaleurneutre)
#DIVIDER
numdecolonneslist = range(1, (len(minmax) + 1))
numdecolonnes = set(numdecolonneslist)
infos = list(zip(numdecolonnes, minmax))
print(
    "\n Informations principales (Numero de la case/colonne sur la grille, [Note 1e pianiste, Note 2 pianiste])]: \n",
    infos,
)
print("\n Note la plus basse de la partition:", notemin)
print("Note la plus haute de la partition:", notemax)
print("Valeur de l'ecart neutre:", valeurecartneutre)
print("Hauteur des ecarts par rapport a la valeur neutre:", positionecarts)
#DIVIDER
len_ecarts = len(ecarts)
largeury = (1 / x) * 10  # largeur équivaut au nombre de notes, ramené sur 10
longueurx = (1 / (x + 1)) * 10  # longueur équivaut au nombre de temps, ramené sur 10
ecarts_copie1 = ecarts[:]
positionecarts_copie1 = positionecarts[:]
#DIVIDER
for i in range(0, x + 1):  # nbr de temps, en x
    for j in range(0, x):  # nbr de notes dans la partition, en y
        make_cube(
            (i / (x + 1) * 10, j / x * 10, 0), (longueurx, largeury, 1), "Pianiste1"
        )  # coord, size, name
pianiste1_liste = get_highest("Pianiste1")
#DIVIDER
for k in range(0, len_ecarts):
    for pianiste1 in pianiste1_liste:
        if len(ecarts_copie1) > 0:  # tant que ecarts_copie contient des elements
            z_scale = ecarts_copie1.pop(k) - positionecarts_copie1.pop(
                k
            )  # la hauteur = un écart (qui est ensuite enlevé de la liste avec pop) - valeur axe z de l'écart
            pianiste1.dimensions.z *= (
                ((x / 2) - (z_scale / 2)) / x
            ) * 10  # hauteur = moitie du cube - la moitie de l'écart (note: x/2 = moitie hauteur cube pour code dynamique, 6 par défaut
            pianiste1.location.z -= (z_scale / x * 10) / 4 - (
                x / 4
            ) / x * 10  # ajuste la position z de la colonne
#DIVIDER
ecarts_copie2 = ecarts[:]
positionecarts_copie2 = positionecarts[:]
#DIVIDER
for i in range(0, x + 1):  # nbr de temps, en x
    for j in range(0, x):  # nbr de notes dans la partition, en y
        make_cube(
            (i / (x + 1) * 10, j / x * 10, 0), (longueurx, largeury, 1), "Pianiste2"
        )  # coord, size, name
pianiste2_liste = get_highest("Pianiste2")
#DIVIDER
for k in range(0, len_ecarts):
    for pianiste2 in pianiste2_liste:
        if len(ecarts_copie2) > 0:  # tant que ecarts_copie contient des elements
            z_scale = ecarts_copie2.pop(k) + positionecarts_copie2.pop(
                k
            )  # la hauteur = un écart (qui est ensuite enlevé de la liste avec pop) + valeur axe z de l'écart
            pianiste2.dimensions.z *= (
                ((x / 2) - z_scale / 2) / x
            ) * 10  # hauteur = moitie du cube - la moitie de l'écart
            pianiste2.location.z += (z_scale / x * 10) / 4 + (
                x / 4
            ) * 3 / x * 10  # ajuste la position z de la colonne
#DIVIDER
#DIVIDER
#DIVIDER
axoCam("axonometrique", "trimetrie")
#DIVIDER
Fonctions pour cube
Operations on cube
list with all objects with ‘name’ given as function parameter
makes a list of the value of the z coordinate of all the objects in objects_list and returns the maximum value of that list with the operation max()
iterates trough the objects_list and if the objects location in z esuals max_z
PROGRAMME
PARTITION DE BASE
partition = [1, 2, 5, 6, 7, 2, 1, 6, 5, 2, 7, 6, 1, 2, 5, 6, 7, 2, 5, 6, 3, 4, 6, 7] nompartition = ‘Partition complète de Piano Phase’ modificateur = 2
partition = [1, 2, 5, 6, 7, 2, 5, 6] nompartition = ‘Piano Phase Partie 2’ modificateur = 1
partition = [3, 4, 6, 7] nompartition = ‘Piano Phase Partie 3’ modificateur = .5
partition = [9, 8, 9, 8, 7, 8, 7, 6, 6, 7, 6, 9, 6, 5, 6, 5, 4, 5, 4, 3, 13, 14, 14, 13, 12, 13, 12, 11, 12, 11] nompartition = ‘Debussy - Clair de lune’ modificateur = 3
partition = [2, 1, 3, 9, 6] nompartition = ‘Rencontre du 3e type’ modificateur = .5
GENERER A PARTIR DE LA PARTITION DE BASE LE MORCEAU JOUE PAR LE PREMIER PIANISTE
GENERER LE MORCEAU JOUE PAR LE DEUXIEME PIANISTE
LISTE DE TOUS LES ECARTS DE NOTES AUX MEMES MOMENTS
GENERER LISTE AVEC POUR CHAQUE MOMENT LES DEUX NOTES JOUEES PAR LES DEUX PIANISTES
CONNAITRE L’ECART MAXIMUM POSSIBLE ET MODIFIER LA POSITION DE L’ECART EN FONCTION DE SA VALEUR
infos console
GENERER PREMIER PIANISTE, STALAGMITES Hauteur des colonnes = moitié du cube - ecart/2 crée un réseau de base de (nbr de notes)x(nbr de temps) avec des cubes de 1x1x1
modifie la hauteur de ce réseau de base
GENERER DEUXIEME PIANISTE, STALACTITES crée un réseau de base de 12x13 avec des cubes de 1x1x1
modifie la hauteur de ce réseau de base
Fin du programme
Bonus GENERER LE NEGATIF (LE CREUX) EN POSITIF
ecarts_copie3 = ecarts[:]
for i in range(0,x+1): #nbr de temps, en x for j in range(0, x): #nbr de notes dans la partition, en y make_cube((i+20,j,(x/2)),(1,1,1),’Negatif’) #coord, size, name
negatif_liste = get_highest(‘Negatif’)
for k in range(0,len_ecarts): for negatif in negatif_liste: if len(ecarts_copie3) > 0: # tant que ecarts_copie contient des elements z_scale = ecarts_copie3.pop(k) # la hauteur = un écart (qui est ensuite enlevé de la liste avec pop) negatif.dimensions.z *= z_scale # hauteur = ecart
PROJECTION AXONOMETRIQUE#
axoCam (‘axonometrique’,’isometrie’) axoCam (‘axonometrique’,’dimetrie’)
FIN DU SCRIPT